BUILD_DIRS = ulong_extras long_extras perm fmpz fmpz_vec fmpz_poly fmpq_poly \
   fmpz_mat mpfr_vec mpfr_mat nmod_vec nmod_poly \
   arith mpn_extras nmod_mat fmpq fmpq_mat padic fmpz_poly_q \
   fmpz_poly_mat nmod_poly_mat fmpz_mod_poly fmpz_mod_poly_factor \
   fmpz_factor fmpz_poly_factor fft qsieve double_extras generics

LIBS=-L$(CURDIR) -L$(FLINT_MPIR_LIB_DIR) -L$(FLINT_MPFR_LIB_DIR) -L$(FLINT_NTL_LIB_DIR) -L$(FLINT_BLAS_LIB_DIR) -lflint $(EXTRA_LIBS) -lmpfr -lmpir -lm -lpthread
LIBS2=-L$(FLINT_MPIR_LIB_DIR) -L$(FLINT_MPFR_LIB_DIR) -L$(FLINT_NTL_LIB_DIR) -L$(FLINT_BLAS_LIB_DIR) $(EXTRA_LIBS) -lmpfr -lmpir -lm -lpthread
INCS=-I$(CURDIR) -I$(FLINT_MPIR_INCLUDE_DIR) -I$(FLINT_MPFR_INCLUDE_DIR) -I$(FLINT_NTL_INCLUDE_DIR) -I$(FLINT_BLAS_INCLUDE_DIR)

LD_LIBRARY_PATH:=${CURDIR}:${FLINT_MPFR_LIB_DIR}:${FLINT_MPIR_LIB_DIR}:${FLINT_NTL_LIB_DIR}:${FLINT_BLAS_LIB_DIR}:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH
export

SOURCES = clz_tab.c memory_manager.c version.c profiler.c 

HEADERS = $(patsubst %, %.h, $(BUILD_DIRS)) config.h fft_tuning.h fmpz-conversions.h

OBJS = $(patsubst %.c, build/%.o, $(SOURCES))

LIB_OBJS = $(patsubst %, build/%/*.o, $(BUILD_DIRS))
LOBJS = $(patsubst %.c, build/%.lo, $(SOURCES))

LIB_LOBJS = $(patsubst %, build/%/*.lo, $(BUILD_DIRS))
MOD_LOBJS = $(patsubst %, build/%.lo, $(BUILD_DIRS))

LIB_SOURCES = $(patsubst %, %/*.c, $(BUILD_DIRS))

EXMP_SOURCES = $(wildcard examples/*.c)

TEST_SOURCES = $(wildcard test/*.c)

PROF_SOURCES = $(wildcard profile/*.c)

TUNE_SOURCES = $(wildcard tune/*.c)

EXMPS = $(patsubst %.c, %, $(EXMP_SOURCES))

TESTS = $(patsubst %.c, build/%, $(TEST_SOURCES))

PROFS = $(patsubst %.c, %, $(PROF_SOURCES))

TUNE = $(patsubst %.c, %, $(TUNE_SOURCES))

all: library 

clean:
	$(foreach dir, $(BUILD_DIRS), export BUILD_DIR=../build/$(dir); $(MAKE) -C $(dir) clean || exit $$?;)
	rm -f $(OBJS) $(LOBJS) $(TESTS) $(PROFS) $(EXMPS) $(FLINT_LIB) libflint.a
	rm -rf build

distclean: clean
	rm -f config.h fft_tuning.h fmpz-conversions.h Makefile

dist:
	git archive --format tar --prefix flint-2.3/ trunk > ../flint-2.3.tar; gzip ../flint-2.3.tar

profile: $(FLINT_LIB) $(PROF_SOURCES) profiler.o
	mkdir -p build/profile
	$(foreach prog, $(PROFS), $(CC) -O2 -std=c99 $(INCS) $(prog).c profiler.o -o build/$(prog) $(LIBS) || exit $$?;)
	$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir)/profile; export BUILD_DIR=../build/$(dir); $(MAKE) -C $(dir) profile || exit $$?;)

tune: $(FLINT_LIB) $(TUNE_SOURCES)
	mkdir -p build/tune
	$(foreach prog, $(TUNE), $(CC) -O2 -std=c99 $(INCS) $(prog).c -o build/$(prog) $(LIBS) || exit $$?;)
	$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir)/tune; export BUILD_DIR=../build/$(dir); $(MAKE) -C $(dir) tune || exit $$?;)

examples: $(FLINT_LIB) $(EXMP_SOURCES)
	mkdir -p build/examples
	$(foreach prog, $(EXMPS), $(CC) $(CFLAGS) $(INCS) $(prog).c -o build/$(prog) $(LIBS) || exit $$?;)

$(FLINT_LIB): $(LIB_SOURCES) $(SOURCES) $(HEADERS) $(LOBJS) | build build/interfaces
	$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir); export BUILD_DIR=../build/$(dir); export MOD_DIR=$(dir); $(MAKE) -C $(dir) shared || exit $$?;)
	if [ "$(WANT_NTL)" -eq "1" ]; then \
	  make build/interfaces/NTL-interface.lo; \
	  $(CXX) -shared build/interfaces/NTL-interface.lo $(LOBJS) $(MOD_LOBJS) $(LIBS2) -o $(FLINT_LIB); \
	fi
	if [ "$(WANT_NTL)" -ne "1" ]; then \
	  $(CC) -shared $(LOBJS) $(MOD_LOBJS) $(LIBS2) -o $(FLINT_LIB); \
	fi

libflint.a: $(LIB_SOURCES) $(SOURCES) $(HEADERS) $(OBJS) | build build/interfaces
	$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir); export BUILD_DIR=../build/$(dir); export MOD_DIR=$(dir); $(MAKE) -C $(dir) static || exit $$?;)
	if [ "$(FLINT_SHARED)" -eq "0" ]; then \
		touch test/t-*.c; \
		$(foreach dir, $(BUILD_DIRS), touch $(dir)/test/t-*.c;) \
	fi
	if [ "$(WANT_NTL)" -eq "1" ]; then \
		make build/interfaces/NTL-interface.o; \
		$(AR) rcs libflint.a build/interfaces/NTL-interface.o; \
	fi
	$(AR) rcs libflint.a $(OBJS);
	$(foreach mod, $(BUILD_DIRS), $(AR) rcs libflint.a build/$(mod)/*.o || exit $$?;)

library:
	if [ "$(FLINT_SHARED)" -eq "1" ]; then \
		make $(FLINT_LIB); \
	fi
	if [ "$(FLINT_STATIC)" -eq "1" ]; then \
		make libflint.a; \
	fi

check: library test_helpers.o
ifndef MOD
	make $(TESTS)
	$(foreach prog, $(TESTS), $(prog) || exit $$?;)
	$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir)/test; export BUILD_DIR=../build/$(dir); $(MAKE) -C $(dir) check || exit $$?;)
	mkdir -p build/interfaces/test
	if [ "$(WANT_NTL)" -eq "1" ]; then \
		make build/interfaces/test/t-NTL-interface; \
		build/interfaces/test/t-NTL-interface; \
	fi
else
	$(foreach dir, $(MOD), mkdir -p build/$(dir)/test; export BUILD_DIR=../build/$(dir); $(MAKE) -C $(dir) check || exit $$?;)
endif

install: $(FLINT_LIB)
	mkdir -p $(PREFIX)/lib
	mkdir -p $(PREFIX)/include/flint
	if [ "$(FLINT_SHARED)" -eq "1" ]; then \
		cp $(FLINT_LIB) $(PREFIX)/lib; \
	fi
	if [ "$(FLINT_STATIC)" -eq "1" ]; then \
		cp libflint.a $(PREFIX)/lib; \
	fi
	cp *.h $(PREFIX)/include/flint

build:
	mkdir -p build

build/%.lo: %.c | build
	$(CC) $(PICFLAG) $(CFLAGS) $(INCS) -c $< -o $@;

build/%.o: %.c | build
	$(CC) $(CFLAGS) $(INCS) -c $< -o $@;

build/test/%: test/%.c | build/test
	$(CC) $(CFLAGS) $(INCS) $< -o $@ $(LIBS)

build/test:
	mkdir -p build/test

build/interfaces:
	mkdir -p build/interfaces

build/interfaces/NTL-interface.lo: interfaces/NTL-interface.cpp
	$(CXX) $(PICFLAG) $(CFLAGS) $(INCS) -c $< -o $@;

build/interfaces/NTL-interface.o: interfaces/NTL-interface.cpp
	$(CXX) $(CFLAGS) $(INCS) -c $< -o $@;

build/interfaces/test/t-NTL-interface: interfaces/test/t-NTL-interface.cpp
	$(CXX) $(CFLAGS) $(INCS) $< build/interfaces/NTL-interface.o -o $@ $(LIBS);

.PHONY: profile library clean examples tune check distclean dist install all

